export const runPrefixMethod = (element, method) => {
  let usablePrefixMethod
  ['webkit', 'moz', 'ms', 'o', ''].forEach((prefix) => {
    if (usablePrefixMethod) return
    if (prefix === '') {
      // 无前缀，方法首字母小写
      method = method.slice(0,1).toLowerCase() + method.slice(1)
    }
    let typePrefixMethod = typeof element[prefix + method]
    if (typePrefixMethod + '' !== 'undefined') {
      if (typePrefixMethod === 'function') {
        usablePrefixMethod = element[prefix + method]()
      } else {
        usablePrefixMethod = element[prefix + method]
      }
    }
  })
  return usablePrefixMethod
}

export const onPrefixEvent = (element, eventName, callback, capture = false) => {
  if (!element || (typeof callback !== 'function')) return
  let usablePrefixEvent
  ['webkit', 'moz', 'ms', 'o', ''].forEach((prefix) => {
    if (usablePrefixEvent) return
    let typePrefixEvent = typeof element['on' + prefix + eventName]
    if (typePrefixEvent + '' !== 'undefined') {
      usablePrefixEvent = prefix + eventName
      element.addEventListener(prefix + eventName, callback, capture)
    }
  })
  return usablePrefixEvent
}

export const offPrefixEvent = (element, eventName, callback, capture = false) => {
  if (!element || (typeof callback !== 'function')) return
  ['webkit', 'moz', 'ms', 'o', ''].forEach((prefix) => {
    let typePrefixEvent = typeof element['on' + prefix + eventName]
    if (typePrefixEvent + '' !== 'undefined') {
      element.removeEventListener(prefix + eventName, callback, capture)
    }
  })
}

export const polyfillRequestAnimationFrame = () => {
  if (!window.requestAnimationFrame) {
    window.requestAnimationFrame = (
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.msRequestAnimationFrame ||
      function (callback) {
        return window.setTimeout(callback, 1000/60)
      }
    )
  }
}

export const polyfillCancelAnimationFrame = () => {
  if (!window.cancelAnimationFrame) {
    window.cancelAnimationFrame = (
      window.mozCancelAnimationFrame ||
      function (requestID) {
        return window.clearTimeout(requestID)
      }
    )
  }
}

export const scrollTop = (element, from = 0, to, duration = 500, endCallback) => {
  polyfillRequestAnimationFrame()
  const difference = Math.abs(from - to)
  const step = Math.ceil(difference / duration * 50)
  scroll(from, to, step)
  function scroll(start, end, step) {
    if (start === end) {
      endCallback && endCallback()
      return
    }
    let d = (start + step > end) ? end : start + step
    if (start > end) {
      d = (start - step < end) ? end : start - step
    }
    if (element === window) {
      window.scrollTo(d, d)
    } else {
      element.scrollTop = d
    }
    window.requestAnimationFrame(() => scroll(d, end, step))
  }
}

export const random = (min, max, decimal) => {
  let result = Math.random() * (max - min) + min
  result = decimal ? result : parseInt(result)
  return result
}

/**
 * 简单深拷贝
 * @param {*} data
 */
export const deepCopy = (data) => {
  let result = data
  try {
      result = JSON.parse(JSON.stringify(data))
  } catch (err) {
      console.log(err)
  }
  return result
}

/**
 * 将数据字符串转换为文件对象
 * @param {String} dataUrl
 * @param {String} type 1(file对象)/2(blob对象)
 * @param {String} fileName
 * @returns {File/Blob}
 */
export const dataUrl2File = (dataUrl, type, fileName) => {
  let arr = dataUrl.split(',')
  let mime = arr[0].match(/:(.*?);/)[1]
  let bstr = atob(arr[1])
  let n = bstr.length
  let u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  if (type === 1) {
    // 转换成file对象
    return new File([u8arr], fileName, { type: mime })
  } else {
    // 转换成成blob对象
    return new Blob([u8arr], { type: mime })
  }
}

/**
 * 下载文件 - a标签
 * @param {String} from 源地址
 * @param {String} to 目标地址/文件名
 */
export const downloadFileByA = (options) => {
  let from = (options || {}).from
  let to = ((options || {}).to || '').split(/[\\|/]/g).pop()
  let ele = document.createElement('a')
  ele.download = to
  ele.style.display = 'none'
  ele.href = from
  document.body.appendChild(ele)
  ele.click()
  document.body.removeChild(ele)
}

/**
 * 加载图片数据
 * @param {String} param 图片地址或File对象
 * @returns {Object} 返回一个Promise对象
 */
export const loadImage = (param) => {
  return new Promise((resolve, reject) => {
    let paramType = (typeof param)
    if (!param) { reject('图片地址不能为空') }
    else if (paramType === 'string') {
      let imgObj = new Image()
      imgObj.onload = () => { resolve(imgObj) }
      imgObj.onerror = () => { reject('图片加载失败') }
      imgObj.setAttribute('crossOrigin', 'anonymous')
      imgObj.src = param
    }
    else if (paramType === 'object') {
      let fr = new FileReader()
      fr.addEventListener('load', () => {
        let imgObj = new Image()
        imgObj.onload = () => { resolve(imgObj) }
        imgObj.onerror = () => { reject('图片加载失败') }
        imgObj.setAttribute('crossOrigin', 'anonymous')
        imgObj.src = fr.result
      })
      fr.readAsDataURL(param)
    }
    else { reject('图片地址无效') }
  })
}

/**
 * 校验数据是否为ArrayBuffer
 * @param {*} value 数据
 * @returns {Boolean}
 */
 export const isArrayBuffer = (value) => {
  return (typeof ArrayBuffer === 'function') && (value instanceof ArrayBuffer || Object.prototype.toString.call(value) === '[object ArrayBuffer]')
}

/**
* 判断数据类型
* @param {*} param
*/
export const typeOf = (param) => {
  return Object.prototype.toString.call(param).slice(8,-1)
}

/**
 * 时间格式化
 * @param {Number} time
 * @param {String} format
 */
export const formatTime = (time, format = 'dd天hh小时mm分ss秒') => {
  time = parseInt(time) || 0
  let result = format
  let handles = [
    {reg: 'd+', factor: 86400000},
    {reg: 'h+', factor: 3600000},
    {reg: 'm+', factor: 60000},
    {reg: 's+', factor: 1000},
  ]
  handles.forEach(v => {
    if (new RegExp(`(${v.reg})`).test(result)) {
      let val = Math.floor(time / v.factor)
      time = time % v.factor
      result = result.replace(new RegExp(v.reg), val.toString().padStart(2,0))
    }
  })
  return result
}

/**
 * 函数防抖 (只执行最后一次点击)
 * @param fn
 * @param delay
 * @returns {Function}
 * @constructor
 */
export const debounce = (fn, t) => {
  let timer = null
  let delay = t || 500
  return function () {
    let context = this, args = arguments
    clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(context, args)
    }, delay)
  }
}
